package controller;

import java.awt.Color;
import java.util.ArrayList;

import javax.swing.JTextField;

import model.Constants;
import model.HostAddress;
import model.IPAddress;
import model.Octet;
import model.Subnet;
import view.components.BinaryIpTextArea;
import view.components.IPTextArea;
import view.views.dialogContentViews.AddSimpleIPContentPanel;
import view.views.dialogContentViews.SubnetBoxPanel;

/**
 * @author Alexander Müller
 * 
 */
public class Calculator {

	private static Calculator CALCULATOR;

	private Calculator() {
	}

	public static Calculator getInstance() {
		if (CALCULATOR == null) {

			CALCULATOR = new Calculator();

		}
		return CALCULATOR;
	}

	public String convertDecimalToBinary(int decimal) {
		return Integer.toBinaryString(decimal);
	}

	public int convertBinaryToDecimal(String binary) {

		int decimal = 0;
		int binaryValue = 1;

		for (int i = 0; i < binary.length(); i++) {
			decimal += Integer.parseInt(Character.toString(binary
					.charAt((binary.length() - 1) - i))) * binaryValue;
			binaryValue = binaryValue * 2;
		}

		return decimal;

	}

	public void calculateHostRange(HostAddress host, HostAddress newHost) {

		if (!host.getSubnetList().isEmpty()) {
			Octet[] startAddress = host.getSubnetList()
					.get(host.getSubnetList().size() - 1).getBroadcastAddress()
					.getAddressBits();
			
			searchIp(host, newHost, startAddress);
			
		} else {
			searchIp(host, newHost, host.getHostAddress().getAddressBits());
		}
	}

	public void modifyIpTextArea(int firstBit, int secondBit, int thirdBit,
			int fourthBit, SubnetBoxPanel subnetBoxPanel) {
		subnetBoxPanel.getIpText().getTextList().get(0)
				.setText(Integer.toString(firstBit));
		subnetBoxPanel.getIpText().getTextList().get(1)
				.setText(Integer.toString(secondBit));
		subnetBoxPanel.getIpText().getTextList().get(2)
				.setText(Integer.toString(thirdBit));
		subnetBoxPanel.getIpText().getTextList().get(3)
				.setText(Integer.toString(fourthBit));

		for (JTextField element : subnetBoxPanel.getIpText().getTextList()) {
			element.setEditable(false);

		}
		for (JTextField element : subnetBoxPanel.getIpText().getDotList()) {
			element.setBackground(subnetBoxPanel.getBackground());

		}

	}

	public String getIpFromIpTextArea(IPTextArea ipTextArea) {
		String ip = Constants.EMPTY;
		for (int i = 0; i < ipTextArea.getTextList().size(); i++) {
			String content = ipTextArea.getTextList().get(i).getText();


			if (content.equals(null) || content.equals(Constants.EMPTY)) {
				content = Constants.ZERO;
			}

			if (content.length() > 1 && content.startsWith(Constants.ZERO, 0)) {
				content = content.substring(content.length() - 1);
			}

			if (i == 3) {
				ip += content;
			} else {
				ip += content + Constants.POINT;
			}
		}
		return ip;

	}

	public String getIpFromBinaryIpTextArea(BinaryIpTextArea ipTextArea) {
		String ip = Constants.EMPTY;
		for (int i = 0; i < ipTextArea.getTextList().size(); i++) {
			String content = ipTextArea.getTextList().get(i).getText();

			if (content.equals(null) || content.equals(Constants.EMPTY)) {
				content = Constants.ZERO;
			}

			content = Integer.toString(convertBinaryToDecimal(content));

			if (i == 3) {
				ip += content;
			} else {
				ip += content + Constants.POINT;
			}
		}
		return ip;

	}

	private void searchIp(HostAddress host, HostAddress newHost,
			Octet[] startAddress) {

		int firstBit = startAddress[0].getBitValue();
		int secondBit = startAddress[1].getBitValue();
		int thirdBit = startAddress[2].getBitValue();
		int fourthBit = startAddress[3].getBitValue() + 1;

		for (int i = 0; i < host.getRange(); i++) {

			String tempIp = Integer.toString(firstBit) + Constants.POINT
					+ Integer.toString(secondBit) + Constants.POINT
					+ Integer.toString(thirdBit) + Constants.POINT
					+ Integer.toString(fourthBit);

			if (newHost.getHostAddress().getAddress().equals(tempIp)) {
				host.setRange(i);
				break;
			}
			fourthBit++;

			if (fourthBit > 255) {
				fourthBit = 0;
				thirdBit++;
			}
			if (thirdBit > 255) {
				thirdBit = 0;
				secondBit++;
			}
			if (secondBit > 255) {
				secondBit = 0;
				firstBit++;
			}

		}

	}

	public int getSuffixByAddress(IPAddress netAddress) {

		Octet octet = netAddress.getAddressBits(0);
		int ipClass = octet.getBitValue();
		ipClass = calculateIpClass(ipClass);
		int possibleHosts = calculatePossibleHosts(ipClass, netAddress);
		return calculateSuffixByHostNumber(possibleHosts);

	}

	public int getNumberOfMaximumHosts(int suffix) {
		int availableBits = Constants.MAXBITS - suffix;
		return (int) Math.pow(2, availableBits);

	}

	public int calculateSubnetSize(int suffix, IPAddress netAddress) {
		int maxHost = getNumberOfMaximumHosts(suffix) - 2;
		int ipClass = calculateIpClass(netAddress.getAddressBits(0)
				.getBitValue());
		int possibleHost = calculatePossibleHosts(ipClass, netAddress);
		if (maxHost <= possibleHost) {
			return maxHost;
		} else {
			return possibleHost;
		}

	}

	public IPAddress calculateBroadcast(IPAddress netAdress, int hosts) {

		int firstBit = netAdress.getAddressBits(0).getBitValue();
		int secondBit = netAdress.getAddressBits(1).getBitValue();
		int thirdBit = netAdress.getAddressBits(2).getBitValue();
		int fourthBit = netAdress.getAddressBits(3).getBitValue();

		for (double range = 0; range < (hosts + 1); range++) {

			fourthBit++;

			if (fourthBit > 255) {
				fourthBit = 0;
				thirdBit++;
			}
			if (thirdBit > 255) {
				thirdBit = 0;
				secondBit++;
			}
			if (secondBit > 255) {
				secondBit = 0;
				firstBit++;
			}
		}

		return new IPAddress(Integer.toString(firstBit) + Constants.POINT
				+ Integer.toString(secondBit) + Constants.POINT
				+ Integer.toString(thirdBit) + Constants.POINT
				+ Integer.toString(fourthBit));

	}

	public IPAddress calculateSubnetmask(int suffix) {
		String address = Constants.EMPTY;
		int suffixPerOctet = suffix;
		for (int i = 0; i < 4; i++) {
			if (suffixPerOctet >= 8) {

				if (i == 3) {
					address += Constants.OCTETMAX;
				} else {
					address += Constants.OCTETMAX + Constants.POINT;
				}
			} else {
				if (i == 3) {
					address += calculateSubnetOctets(suffixPerOctet);
				} else {
					address += calculateSubnetOctets(suffixPerOctet)
							+ Constants.POINT;
				}

			}
			suffixPerOctet -= 8;
		}
		return new IPAddress(address);
	}

	public int calculateSuffixByHostNumber(int hosts) {
		int freeSuffix = 0;
		for (int i = 0; i < hosts;) {
			i = (int) Math.pow(2, freeSuffix);
			freeSuffix++;
		}
		freeSuffix--;
		return Constants.MAXBITS - freeSuffix;
	}

	public int calculatePossibleHosts(int ipClass, IPAddress netAddress) {
		int hosts = 0, second, third, fourth;
		switch (ipClass) {
		case Constants.CLASS_A:
			second = netAddress.getAddressBits(1).getBitValue();
			third = netAddress.getAddressBits(2).getBitValue();
			fourth = netAddress.getAddressBits(3).getBitValue();
			hosts = calculateHostsByBits(second, third, fourth);
			break;
		case Constants.CLASS_B:
			third = netAddress.getAddressBits(2).getBitValue();
			fourth = netAddress.getAddressBits(3).getBitValue();
			hosts = calculateHostsByBits(Constants.BITMAXVALUE, third, fourth);
			break;
		case Constants.CLASS_C:
			fourth = netAddress.getAddressBits(3).getBitValue();
			hosts = calculateHostsByBits(Constants.BITMAXVALUE,
					Constants.BITMAXVALUE, fourth);
			break;
		}
		return hosts - 2;
	}


	public boolean validateAddress(String newAddress) {
		for (HostAddress element : Controller.getInstance().getHosts()) {
			if (element.getHostAddress().getAddress().equals(newAddress)) {
				return false;
			}
			if (checkSubnet(element.getSubnetList(), newAddress)) {
				return false;
			}
		}
		return true;
	}

	private boolean checkSubnet(ArrayList<Subnet> subnetList, String newAddress) {
		for (Subnet sub : subnetList) {
			if (sub.getNetAdress().getAddress().equals(newAddress)
					|| sub.getBroadcastAddress().getAddress()
							.equals(newAddress)) {
				return true;
			}
			for (IPAddress ip : sub.getIpAddressList()) {
				if (ip.getAddress().equals(newAddress)) {
					return true;
				}
			}
		}
		return false;
	}


	public int calculateIpClass(int firstBit) {
		if (firstBit < 128) {
			return Constants.CLASS_A;
		} else if (firstBit < 191) {
			return Constants.CLASS_B;
		} else {
			return Constants.CLASS_C;
		}
	}

	private int calculateHostsByBits(int second, int third, int fourth) {
		int possibleHosts = Constants.MAXHOSTS;
		possibleHosts -= second * (Constants.BITMAXSQRD);
		possibleHosts -= third * Constants.BITMAX;
		possibleHosts -= fourth;
		return possibleHosts;
	}

	private String calculateSubnetOctets(int suffixPart) {

		int decimal = 0, binary = 256;

		if (suffixPart == 0) {
			return Integer.toString(0);
		} else {
			for (int i = 0; i < suffixPart; i++) {
				binary = binary / 2;
				decimal += binary;

			}
		}

		return Integer.toString(decimal);
	}

	public boolean validateIpTextArea(IPTextArea ipTextArea) {
		for (JTextField element : ipTextArea.getTextList()) {

			if (element.getText().length() > 3
					|| Integer.parseInt(element.getText()) > 256) {
				return false;
			}
		}
		return true;
	}

	
	public String convertIPBinary(IPAddress ipAddress){
		String result = "";
		int i = 0;
		for (Octet octet : ipAddress.getAddressBits()) {
			i++;
			result+=convertDecimalToBinary(octet.getBitValue());
			if(i<4){
			result+=".";}
		}
		return result;
		
	}


	public boolean validateBinaryIpTextArea(BinaryIpTextArea ipTextArea) {
		for (JTextField element : ipTextArea.getTextList()) {
			if (element.getText().length() > 0
					&& element.getText().length() < 9) {
				return true;
			}
		}
		return false;
	}

	public void modifyTextFields(int i, AddSimpleIPContentPanel content) {
		if (i == 0) {
			for (int j = 0; j < content.getBinaryIpTextArea().getTextList()
					.size(); j++) {
				content.getBinaryIpTextArea().getTextList().get(j)
						.setEditable(false);
				content.getIpTextArea().getTextList().get(j).setEditable(true);
				if (j < 3) {
					content.getBinaryIpTextArea().getDotList().get(j)
							.setBackground(content.getBackground());
					content.getIpTextArea().getDotList().get(j)
							.setBackground(Color.white);
				}
			}
		} else {
			for (int j = 0; j < content.getBinaryIpTextArea().getTextList()
					.size(); j++) {
				content.getBinaryIpTextArea().getTextList().get(j)
						.setEditable(true);
				content.getIpTextArea().getTextList().get(j).setEditable(false);
				if (j < 3) {
					content.getBinaryIpTextArea().getDotList().get(j)
							.setBackground(Color.white);
					content.getIpTextArea().getDotList().get(j)
							.setBackground(content.getBackground());
				}
			}

		}
	}

}
